#include "gm_sc_dev.h"
#include "../gm_api/gm_defs.h"
#include <middleware/apdu/apdu.lib/apdu_lib.h>
#include <middleware/mk_lib/mk_utility.h>
#include <middleware/mk_lib/mk_logger.h>

#define APDU_MAX_DATA_UNIT 1024

//#define HS_MAX_DATA_UNIT  0x1400

//ULONG gm_sc_dev::s_currentHandle = 0x1000;

gm_sc_dev::gm_sc_dev(void)
{
	_bconnected = 0;
	_apdu_handle	= 0;
	_AuthAlgId = 0;
	_bconnected = 0;
	_bauth = 0;
	memset(_name, 0, sizeof(_name));

	_max_apdu_len = APDU_MAX_DATA_UNIT;
	_max_hs_data_len = 0;
	init_handle(DEVICE_HANDLE);
}

gm_sc_dev::gm_sc_dev(char *name)
{
	_bconnected = 0;
	_apdu_handle	= 0;
	_AuthAlgId = 0;
	_bconnected = 0;
	_bauth = 0;
	strcpy(_name, name);

	_max_apdu_len = APDU_MAX_DATA_UNIT;
	_max_hs_data_len = 0;

	init_handle(DEVICE_HANDLE);
}


gm_sc_dev::gm_sc_dev(char *name, HANDLE handle)
{
	_bconnected = 0;
	_apdu_handle	= handle;
	_AuthAlgId = 0;
	_bconnected = 0;
	_bauth = 0;
	strcpy(_name, name);

	_max_apdu_len = APDU_MAX_DATA_UNIT;
	_max_hs_data_len = 0;

	init_handle(DEVICE_HANDLE);
}

gm_sc_dev::~gm_sc_dev(void)
{
	//disconnect();
}


int gm_sc_dev::lock_dev(ULONG ulTimeOut)
{
	return app_lock_device(_apdu_handle, ulTimeOut);
}
int gm_sc_dev::unlock_dev()
{
	return app_unlock_device(_apdu_handle);
}

int gm_sc_dev::begin_transaction()
{
	return app_begin_transaction(_apdu_handle);
}

int gm_sc_dev::end_transaction()
{
	return app_end_transaction(_apdu_handle);
}

gm_sc_key * gm_sc_dev::find_key( HANDLE hKey, gm_sc_app *& pApp, gm_sc_cont *& pContainer)
{
	gm_sc_key * pKey = NULL;
	gm_sc_app_mgr *app_mgr = get_app_mgr();
	gm_sc_app *sc_app = app_mgr->get_first_app();

	while(sc_app)
	{
		pKey = sc_app->find_key(hKey, pContainer);
		if(pKey) 
		{
			pApp = sc_app;
			break;
		}

		sc_app = app_mgr->get_next_app();
	}

	return pKey;
}


gm_sc_mac * gm_sc_dev::find_mac( HANDLE hMac, gm_sc_app *& pApp, gm_sc_cont *& pContainer )
{
	gm_sc_mac * pMac = NULL;
	gm_sc_app_mgr *app_mgr = get_app_mgr();
	gm_sc_app *sc_app = app_mgr->get_first_app();

	while(sc_app)
	{
		pMac = sc_app->find_mac(hMac, pContainer);
		if(pMac) 
		{
			pApp = sc_app;
			break;
		}

		sc_app = app_mgr->get_next_app();
	}

	return pMac;
}

gm_sc_cont * gm_sc_dev::find_container( HCONTAINER hContainer, gm_sc_app *& pApp )
{
	gm_sc_app_mgr *app_mgr = get_app_mgr();
	gm_sc_app *sc_app = app_mgr->get_first_app();
	
	gm_sc_cont * pContainer = NULL;
	while(sc_app)
	{
		pContainer = sc_app->find_container(hContainer);
		if(pContainer)
		{
			pApp = sc_app;
			return pContainer;
		}
		sc_app = app_mgr->get_next_app();
	}
	
	return NULL;
}

gm_sc_app * gm_sc_dev::find_app( HAPPLICATION hApplication )
{
	gm_sc_app_mgr *app_mgr = get_app_mgr();
	gm_sc_app *sc_app = app_mgr->get_first_app();

	while(sc_app)
	{
		if(hApplication == sc_app->get_handle())
		{
			return sc_app;
		}

		sc_app = app_mgr->get_next_app();
	}

	return NULL;
}



gm_sc_app * gm_sc_dev::find_app_by_name( char * appName )
{
	gm_sc_app_mgr *app_mgr = get_app_mgr();
	gm_sc_app *sc_app = app_mgr->get_first_app();

	while(sc_app)
	{
		if(strcmp(sc_app->Name(), appName) == 0)
		{
			return sc_app;
		}

		sc_app = app_mgr->get_next_app();
	}

	return NULL;
}


gm_sc_digest * gm_sc_dev::find_digest( HANDLE hDigest )
{
	gm_handle_mgr *digest_mgr = get_digest_mgr();
	gm_handle *sc_digest = digest_mgr->get_first_handle();

	while(sc_digest)
	{
		if(hDigest == sc_digest->get_handle())
		{
			return (gm_sc_digest *)sc_digest;
		}

		sc_digest = digest_mgr->get_next_handle();
	}

	return NULL;
}

gm_sc_app * gm_sc_dev::create_app( AppInfoRsp appinfo, LPSTR appName )
{
	gm_sc_app* papp = new gm_sc_app(appinfo, appName);
	_sc_app_mgr.add_app(papp);

	return papp;
}

ULONG gm_sc_dev::remove_app( gm_sc_app * pApp )
{
	return _sc_app_mgr.remove_app(pApp);
}

ULONG gm_sc_dev::remove_app( LPSTR appName )
{
	return _sc_app_mgr.remove_app_by_name(appName);
}

gm_sc_digest * gm_sc_dev::create_digest( ULONG ulAlgId )
{
	gm_sc_digest *pdigest = new gm_sc_digest(ulAlgId);
	get_digest_mgr()->add_handle(pdigest);
	return pdigest;
}

ULONG gm_sc_dev::remove_digest( gm_sc_digest *pDigest )
{
	return get_digest_mgr()->remove_handle(pDigest);
}

ULONG gm_sc_dev::connect()
{
	long maxHSLen = 0;
	ULONG lRslt = app_connect_device_by_name(_name, &_apdu_handle);
	if(lRslt != SAR_OK)
		return lRslt;

	IsConnected(TRUE);

	cosDevInfo		devInfo = {0};
	lRslt = app_get_dev_info(_apdu_handle, (unsigned char*)&devInfo, sizeof(devInfo));
	ERROR_THROW_APDU(lRslt)


	_max_apdu_len = devInfo.MaxApduDataLen;
	mk_utility::reverse_bytes(&_max_apdu_len, 2);

	_max_apdu_len -= 32;

	

	lRslt = app_dev_get_hs_data_size(_apdu_handle, &maxHSLen);
	DBG_LOGMSG("app_dev_get_hs_data_size ret = %08x, hs_len = %d", lRslt, maxHSLen);
	if(lRslt == SAR_OK)
	{
		_max_hs_data_len = maxHSLen;
	}
	set_max_transmit_len(get_max_apdu_len());

	if(devInfo.HWVersion.major < 2) //AS508 
	{
		set_max_io_delay(3);
	}
	else
	{
		set_max_io_delay(0); //as518
	}
	
END_OF_FUN:

	return lRslt;
}

//for CCID device
ULONG gm_sc_dev::connect( char * devPath, HANDLE hCard )
{
	char devName[64]={0};
	long maxHSLen = 0;
	ULONG lRslt = 0;

	_apdu_handle = app_add_exist_device(devPath, hCard);
	if(_apdu_handle == NULL)
		return 1;

	IsConnected(TRUE);

	cosShortDevInfo devInfo = {0};
	lRslt = app_get_dev_short_info(_apdu_handle, (unsigned char*)&devInfo, sizeof(devInfo));

	if(lRslt != 0 && get_last_sw() == 0x6F00) //not formatted
	{
		lRslt = 0;
	}	

	ERROR_THROW_APDU(lRslt);

	_max_apdu_len = 1024;

	set_max_transmit_len(get_max_apdu_len());

	memcpy(devName, devInfo.SerialNumber, 32);
	DBG_LOGMSG("devName :%s ",  devName);
	app_set_dev_name(_apdu_handle, devName);

	if(devInfo.HWVersion.major < 2) //AS508 
	{
		set_max_io_delay(3);
	}
	else
	{
		set_max_io_delay(0); //as518
	}

END_OF_FUN:

	return lRslt;
}

ULONG gm_sc_dev::disconnect()
{	
	ULONG lRslt = SAR_OK;
	if(_apdu_handle)
	{
		lRslt = app_disconnect_device(_apdu_handle);
		_apdu_handle = NULL;
	}

	IsConnected(FALSE);
	return lRslt;
}

ULONG gm_sc_dev::get_interface_type()
{
	long type;
	app_dev_get_type(_apdu_handle, &type);

	return type;
}

gm_sc_key * gm_sc_dev::get_first_key( gm_sc_app *&pApp, gm_sc_cont *&pContainer )
{
	pApp = get_app_mgr()->get_first_app();
	if(pApp != NULL)
	{
		pContainer = pApp->get_first_container();
		if(pContainer != NULL)
		{
			return pContainer->get_first_key();
		}
	}
	return NULL;
}

HANDLE gm_sc_dev::get_dev_os_handle()
{
	HANDLE osHandle = 0;
	app_get_dev_os_handle(_apdu_handle, &osHandle);

	return osHandle;
}

ULONG gm_sc_dev::get_dev_os_path(char devPath[260])
{
	if(0 != app_dev_get_os_path(_apdu_handle, devPath))
	{
		return 1;
	}
	
	return 0;
}

BOOL gm_sc_dev::if_support_hs()
{
	if(_max_hs_data_len > _max_apdu_len)
		return 1;

	return 0;
}


